#include "Transform.hpp"

#include <glm/gtx/euler_angles.hpp>

Transform::Transform(const glm::vec3 & translation,
                     const glm::vec3 & rotation)
  : m_rotation(rotation)
{
  m_translationMatrix = glm::translate(mat4(1.0f), translation);
  
  vec3 rotationRadians = glm::radians(m_rotation);
  m_modelMatrix = m_translationMatrix * glm::eulerAngleX(rotationRadians.x) *
                                        glm::eulerAngleY(rotationRadians.y);
}

Transform::Transform(const glm::mat4 & matrix)
  : m_rotation(0.0f, 0.0f, 0.0f), m_modelMatrix(matrix), m_translationMatrix(1.0f)
{
  m_translationMatrix[3] = matrix[3];
  m_rotation.x = glm::degrees(glm::acos(matrix[1][1]));
  m_rotation.y = glm::degrees(glm::acos(matrix[0][0]));
}

glm::vec3 Transform::getTranslation() const
{
  return vec3(m_translationMatrix[3].x,
              m_translationMatrix[3].y,
              m_translationMatrix[3].z);
}

glm::mat4 Transform::getTranslationMatrix() const
{
  return m_translationMatrix;
}

glm::vec2 Transform::getRotation() const
{
  return vec2(m_rotation.x, m_rotation.y);
}

glm::mat4 Transform::getModelMatrix()
{
  return m_modelMatrix;
}

void Transform::transform(const glm::vec3 & displacement,
                          const glm::vec3 & rotation)
{
  m_rotation += rotation;
  
  if (m_rotation.x > 90.0f) {
    m_rotation.x = 90.0f;
  } else if (m_rotation.x < -90.0f){
    m_rotation.x = -90.0f;
  }

  if (m_rotation.y > 180.0f) {
    m_rotation.y -= 360.0f;
  } else if (m_rotation.y <= -180.0f){
    m_rotation.y += 360.0f;
  }
  
  if (m_rotation.z > 180.0f) {
    m_rotation.z -= 360.0f;
  } else if (m_rotation.z <= -180.0f){
    m_rotation.z += 360.0f;
  }
  
  mat4 rotationMatrix = glm::rotate(mat4(1.0f), m_rotation.x, vec3(0.1f, 0.0f, 0.0f)) *
                        glm::rotate(mat4(1.0f), m_rotation.y, vec3(0.0f, 1.0f, 0.0f));
                  
  m_modelMatrix = glm::translate(mat4(1.0f), displacement) * 
                  rotationMatrix *
                  m_translationMatrix;
                  
  m_translationMatrix = glm::transpose(rotationMatrix) * m_modelMatrix;
}

void Transform::set(const glm::vec3 & displacement,
                          const glm::vec3 & rotation)
{
  m_modelMatrix = mat4(1.0f);
  m_rotation = vec3(1.0f,1.0f,1.0f);
  m_translationMatrix = mat4(1.0f);
  transform(displacement, rotation);
}
